package cn.com.surker.workcon.service.siwei;

import cn.com.surker.base.system.dao.SysStorageLogDao;
import cn.com.surker.base.system.entity.SysLine;
import cn.com.surker.base.system.entity.SysStorageLog;
import cn.com.surker.control.entity.ControlExpend;
import cn.com.surker.enums.StateEnum;
import cn.com.surker.external.entity.LabExpendB;
import cn.com.surker.lab.dao.LabLevelOptimizeDao;
import cn.com.surker.lab.dao.LabLevelOptimizeMaterialDao;
import cn.com.surker.lab.entity.*;
import cn.com.surker.lab.vo.LabExpendVoB;
import cn.com.surker.util.DateUtil;
import cn.com.surker.util.MathUtils;
import cn.com.surker.util.StringUtils;
import cn.com.surker.workcon.common.GKJDBCService;
import cn.com.surker.workcon.common.OptimizeUtil;
import cn.com.surker.workcon.service.DosageService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.annotation.Resource;
import java.util.*;

/**
 * <p>
 * 上海思维消耗信息 Mapper 接口
 * </p>
 *
 * @author admin
 * @since 2024-09-26
 */
public class DosageServiceImpl extends GKJDBCService implements DosageService {

	@Resource
	private SysStorageLogDao sysStorageLogDao;

	@Resource
	private LabLevelOptimizeDao labLevelOptimizeDao;

	@Resource
	private LabLevelOptimizeMaterialDao labLevelOptimizeMaterialDao;

	//	原始消耗表
	private String dosage = "TJlbYcl";
	//	备份的真实消耗表
	// private String realDosage = "TJlbYcl_B";
	private String realDosage = "TJlbYcl";

	/**
	 * 根据盘id,查询工控机消耗信息
	 * 实现AB库,需要
	 * 1.先实现备份原始消耗数据后,清除原始表的盘消耗记录
	 * 2.同步真实数据到erp中的A库
	 * 3.在同步数据的时候,根据配合比,模拟b库的数据
	 *
	 *
	 * @param pieId
	 * @param batchStere
	 * @return
	 */
	public List<LabExpend> findByPieId(Long lineId, Long invoiceId, Long batchId, String prodId, String pieId, Date batTime,
									   Double batchStere, Long formulaId, Double formulaWater, Long levelOptimizeId, Date createDate) {
		if (lineId == null || StringUtils.isBlank(pieId)) {
			return null;
		}
		SysLine line = getLine(lineId);
		if (line == null) {
			return null;
		}
		JdbcTemplate lineJdbcTemp = getLineJdbcTemp(line);
		// 创建假数据
		if (levelOptimizeId == null) {
			//	没有假数据,返回空,后期是否提示
			return null;
		}
		//	模拟消耗数据
		// simulateDosage(lineId, invoiceId, batchId, prodId, pieId, batTime, batchStere, lineJdbcTemp, levelOptimizeId, createDate);
		//	查询真实消耗
		List<LabExpend> expendList = findRealByPieId(lineId, invoiceId, batchId, prodId, pieId, batTime, formulaId, formulaWater, lineJdbcTemp, createDate);
		return expendList;
	}


	/**
	 * 查询工控机消耗只需要查询真实数据
	 *
	 * @param lineId     生产线id
	 * @param batchId    erp里面的备份工控消耗表里面的盘id
	 * @param prodId     工控机id
	 * @param pieId      盘id
	 * @param batTime
	 * @param createDate
	 * @return
	 */
	@Override
	public List<ControlExpend> findWorkByPieId(Long lineId, Long batchId, String prodId, String pieId, Date batTime, Date createDate) {
		if (lineId == null || StringUtils.isBlank(pieId)) {
			return null;
		}
		SysLine line = getLine(lineId);
		if (line == null) {
			return null;
		}
		JdbcTemplate lineJdbcTemp = getLineJdbcTemp(line);
		//	查询sql
		String querySql = "select FNo,FPanNo,FBh,FYlmc,FPzgg,FPbsl,FSysl,FHsl,FGlyl,FBs0,FEzt,FEID from " + realDosage + " where fno = ? and FPanNo = ?;";
		//	(将盘号转为数字第几盘)
		int fpanNo = Integer.valueOf(pieId);
		Object[] param = {prodId, fpanNo};
		List<Map<String, Object>> dosageList = lineJdbcTemp.queryForList(querySql, param);
		if (dosageList == null || dosageList.isEmpty()) {
			return null;
		}
		List<ControlExpend> expendList = new ArrayList<>();
		for (int i = 0, s = dosageList.size(); i < s; i++) {
			Map<String, Object> dosage = dosageList.get(i);
			//	工控机的记录号
			String conExpendId = String.valueOf(dosage.get("FEID"));
			//	工控机的料仓信息,根据料仓信息查询出当前消耗的材料
			String storage = String.valueOf(dosage.get("FYlmc"));
			//	工控机的原料
			String bcsMaterial = String.valueOf(dosage.get("FYlmc"));
			String batchTime = "";
			if (batTime != null) {
				batchTime = DateUtil.convertString(batTime);
			}
			Long erpMaterialId = null;
			Long erpStorageId = null;
			SysStorageLog takeTimeOrStorage = sysStorageLogDao.findTakeTimeOrStorage(lineId, bcsMaterial, 1, batchTime);
			if (takeTimeOrStorage != null) {
				String erpMaterial = takeTimeOrStorage.getMaterial();
				erpMaterialId = takeTimeOrStorage.getMaterialId();
				erpStorageId = takeTimeOrStorage.getStorageId();
			}
			//	工控机的配方值
			Double recAmnt = Double.valueOf(String.valueOf(dosage.get("FPbsl")));
			//	工控机的设定值
			Double planAmnt = Double.valueOf(String.valueOf(dosage.get("FPbsl")));
			//	工控机的实际值
			Double factAmnt = Double.valueOf(String.valueOf(dosage.get("FSysl")));
			//	工控机的含水率
			Double watFull = Double.valueOf(String.valueOf(dosage.get("FHsl")));
			if (watFull != null && watFull != 0d) {
				watFull = MathUtils.divide(watFull, 100d);
			}
			ControlExpend expend = new ControlExpend();
			expend.setLineId(lineId);
			expend.setErpBatchId(batchId);
			expend.setStorage(storage);
			expend.setMaterial(bcsMaterial);
			expend.setErpMaterialId(erpMaterialId);
			expend.setErpStorageId(erpStorageId);
			expend.setFormulaQuantity(recAmnt);
			expend.setControlSetQuantity(planAmnt);
			expend.setControlRealQuantity(factAmnt);
			expend.setControlWater(watFull);
			expend.setUseTime(batTime);
			expend.setStatus(StateEnum.ENABLED.getCode());
			expend.setCreator(bcsCreater);
			expend.setCreateTime(createDate);
			expend.setConExpendNo(conExpendId);
			expendList.add(expend);
		}
		return expendList;
	}

	@Override
	public List<LabExpendOther> findAll(Long lineId) {
		return null;
	}

	/**
	 * 查询真实消耗,返回的也应该是真实消耗
	 *
	 * @param lineId
	 * @param invoiceId
	 * @param batchId
	 * @param prodId
	 * @param pieId
	 * @param batTime
	 * @param formulaId
	 * @param formulaWater
	 * @param lineJdbcTemp
	 * @param createDate
	 * @return
	 */
	private List<LabExpend> findRealByPieId(Long lineId, Long invoiceId, Long batchId, String prodId, String pieId, Date batTime,
											Long formulaId, Double formulaWater, JdbcTemplate lineJdbcTemp, Date createDate) {
		//	查询sql
		String querySql = "select FNo,FPanNo,FBh,FYlmc,FPzgg,FPbsl,FSysl,FHsl,FGlyl,FBs0,FEzt,FEID from " + realDosage + " where fno = ? and FPanNo = ?;";
		//	(将盘号转为数字第几盘)
		int fpanNo = Integer.valueOf(pieId);
		Object[] param = {prodId, fpanNo};
		List<Map<String, Object>> dosageList = lineJdbcTemp.queryForList(querySql, param);
		if (dosageList == null || dosageList.isEmpty()) {
			return null;
		}
		//	转换数据
		String batchTime = "";
		if (batTime != null) {
			batchTime = DateUtil.convertString(batTime);
		}
		List<LabExpend> expendList = new ArrayList<>();
		for (int i = 0, s = dosageList.size(); i < s; i++) {
			Map<String, Object> dosage = dosageList.get(i);
			//	工控机的记录号
			String conExpendId = String.valueOf(dosage.get("FEID"));
			//	工控机的料仓信息,根据料仓信息查询出当前消耗的材料
			String storage = String.valueOf(dosage.get("FYlmc"));
			//	工控机的原料
			String bcsMaterial = String.valueOf(dosage.get("FYlmc"));
			//	erp的原料id
			Long erpMaterialId = null;
			//	工控机的原料id
			Long erpStorageId = null;
			SysStorageLog takeTimeOrStorage = sysStorageLogDao.findTakeTimeOrStorage(lineId, bcsMaterial, 1, batchTime);
			if (takeTimeOrStorage != null) {
				String erpMaterial = takeTimeOrStorage.getMaterial();
				erpMaterialId = takeTimeOrStorage.getMaterialId();
				erpStorageId = takeTimeOrStorage.getStorageId();
			}
			//	工控机的配方值(配合比设定值)
			Double recAmnt = Double.valueOf(String.valueOf(dosage.get("FPbsl")));
			//	工控机的设定值
			Double planAmnt = Double.valueOf(String.valueOf(dosage.get("FPbsl")));
			//	工控机的实际值(实际称量值)
			Double factAmnt = Double.valueOf(String.valueOf(dosage.get("FSysl")));
			//	工控机的含水率
			Double watFull = Double.valueOf(String.valueOf(dosage.get("FHsl")));
			if (watFull != null && watFull != 0d) {
				watFull = MathUtils.divide(watFull, 100d);
			}
			LabExpend expend = new LabExpend();
			expend.setInvoiceId(invoiceId);
			expend.setLineId(lineId);
			expend.setMaterialId(erpMaterialId);
			expend.setStorageId(erpStorageId);
			expend.setControlStorage(storage);
			expend.setBatchId(batchId);
			expend.setFormulaId(formulaId);
			expend.setFormulaQuantity(recAmnt);
			expend.setFormulaWater(formulaWater);
			expend.setControlSetQuantity(planAmnt);
			expend.setControlRealQuantity(factAmnt);
			expend.setControlWater(watFull);
			expend.setCreator(bcsCreater);
			expend.setCreateTime(createDate);
			expend.setUseTime(batTime);
			expend.setConExpendId(conExpendId);
			expendList.add(expend);
		}
		return expendList;
	}

	/**
	 * 模拟消耗数据
	 *
	 * @param lineId           生产线id
	 * @param invoiceId        发货抵
	 * @param batchId          盘抵
	 * @param prodId           工控机发货单id
	 * @param pieId            工控机盘id
	 * @param batTime          盘消耗时间
	 * @param lineJdbcTemp     数据源
	 * @param levelOptimizeId 优化配合比库
	 * @param createDate       创建时间
	 */
	private void simulateDosage(Long lineId, Long invoiceId, Long batchId, String prodId, String pieId, Date batTime, Double batchStere,
								JdbcTemplate lineJdbcTemp, Long levelOptimizeId, Date createDate) {
		//	(将盘号转为数字第几盘)
		int fpanNo = Integer.valueOf(pieId);
		//	优化配合比id
		if (levelOptimizeId == null) {
			return;
		}
		//	查询优化配合比
		LabLevelOptimize labLevelOptimize = labLevelOptimizeDao.selectById(levelOptimizeId);
		if (labLevelOptimize == null) {
			return;
		}
		//	查询优化配合比下的材料
		QueryWrapper<LabLevelOptimizeMaterial> query = new QueryWrapper<>();
		query.eq("status", 0);
		query.eq("level_optimize_id", levelOptimizeId);
		query.orderByAsc("id");
		List<LabLevelOptimizeMaterial> constructMaterialList = labLevelOptimizeMaterialDao.selectList(query);
		if (constructMaterialList == null || constructMaterialList.isEmpty()) {
			//	优化配合比下没有材料
			return;
		}
		//	转换数据
		String batchTime = "";
		if (batTime != null) {
			batchTime = DateUtil.convertString(batTime);
		}
		//	==========创建优化数据逻辑==========
		//	1.查询优化配合比下的材料类型
		//	2.根据该材料类型,查询erp中当前匹配的工控机下的仓位
		//	3.从工控机的仓位中,随机选择一个仓位
		//	4.设置用量,设置上下浮动
		// ===================================
		//	材料设定用量
		Map<String, Double> newUsedMap = new HashMap<>();
		//	材料实际用量
		Map<String, Double> newOptMap = new HashMap<>();
		//	根据材料,查询材料下的工控机仓位
		for (LabLevelOptimizeMaterial optimizeMaterial : constructMaterialList) {
			//	标准配合比的材料名称
			Long materialType = optimizeMaterial.getMaterialType();
			//	查询工控机的仓位
			List<SysStorageLog> wcStorageList = sysStorageLogDao.findWcStorage(lineId, materialType, batchTime);
			if (wcStorageList == null || wcStorageList.isEmpty()) {
				wcStorageList = sysStorageLogDao.findWcStorage(lineId, materialType, null);
			}
			//	随机工控机仓位
			SysStorageLog sysStorageLog = OptimizeUtil.simulateStorage(lineId, materialType, wcStorageList);
			if (sysStorageLog == null) {
				//	没有材料的仓位
				return;
			}
			//	工控机仓位
			String wcStorage = sysStorageLog.getNewStorage();
			//	取出用量
			Double used = optimizeMaterial.getUsed();
			if (used == null || used.equals(0d)) {
				//	没有用量
				continue;
			}
			//	取出旧的值
			Double oldUValue = newUsedMap.get(wcStorage);
			if (oldUValue != null) {
				used = MathUtils.add(used, oldUValue);
			}
			//	设置材料用的值
			newUsedMap.put(wcStorage, used);
			//	计算工控机消耗值
			Double optValue = OptimizeUtil.simulateUsed(batchStere, used, null, null);
			//	设置材料用的真实值
			newOptMap.put(wcStorage, optValue);
			/*//	erp的原料id
			Long erpMaterialId = sysStorageLog.getMaterialId();
			//	erp的仓位id
			Long erpStorageId = null;
			SysStorageLog takeTimeOrStorage = sysStorageLogDao.findTakeTimeOrStorage(lineId, wcStorage, 0, batchTime);
			if (takeTimeOrStorage != null){
				erpStorageId = takeTimeOrStorage.getStorageId();
			}*/
		}
		//	待添加消耗数据
		List<Object[]> newDosageList = new ArrayList<>();
		Set<String> wcStorageList = newOptMap.keySet();
		for (String wcStorage : wcStorageList) {
			//	理论值
			Double FPbsl = newUsedMap.get(wcStorage);
			//	实际值
			Double FSysl = newOptMap.get(wcStorage);
			//	创建消耗值
			Object[] dosage = {prodId, fpanNo, wcStorage, FPbsl, FSysl, FSysl, FSysl};
			newDosageList.add(dosage);
		}
		if (newDosageList.isEmpty()) {
			return;
		}
		//	插入数据
		String insertSql = "INSERT INTO " + dosage + " (FNo,FPanNo,FYlmc,FPbsl,FSysl,FHsl,FGlyl)\n" +
			"Values(?,?,?,?,?,?,?);";
		lineJdbcTemp.batchUpdate(insertSql, newDosageList);
		//	删除第0盘的数据
		String del0Sql = "delete from " + dosage + " where FPanNo = 0 and FNo = " + pieId;
		lineJdbcTemp.update(del0Sql);
		//	统计第0盘数据
		String cenus0pan = "select FYlmc,SUM(FPbsl) FPbsl,SUM(FSysl) FSysl,SUM(FHsl) FHsl,SUM(FGlyl) FGlyl from TJlbYcl where fno = " + prodId + " and fpanno != 0 group by FYlmc";
		List<Map<String, Object>> cenus0panDatas = lineJdbcTemp.queryForList(cenus0pan);
		if (cenus0panDatas != null && cenus0panDatas.size() > 0) {
			//	插入0盘数据
			Map<String, Object> cenus0panData = cenus0panDatas.get(0);
			String insert0Sql = "INSERT INTO " + dosage + " (FNo,FPanNo,FYlmc,FPbsl,FSysl,FHsl,FGlyl)\n" +
				"Values(?,?,?,?,?,?,?);";
			Object FYlmc = cenus0panData.get("cenus0panData");
			Object FPbsl = cenus0panData.get("FPbsl");
			Object FSysl = cenus0panData.get("FSysl");
			Object FHsl = cenus0panData.get("FHsl");
			Object FGlyl = cenus0panData.get("FGlyl");
			Object[] dosage = {prodId, fpanNo, FYlmc, FPbsl, FSysl, FHsl, FGlyl};
			lineJdbcTemp.update(insert0Sql, dosage);
		}
		//	重新查询真实库的sql
		String querySql = "select FNo,FPanNo,FBh,FYlmc,FPzgg,FPbsl,FSysl,FHsl,FGlyl,FBs0,FEzt,FEID from " + dosage + " where fno = ? and FPanNo = ?;";
		Object[] param = {prodId, fpanNo};
		List<Map<String, Object>> wcDosageList = lineJdbcTemp.queryForList(querySql, param);
		if (wcDosageList == null || wcDosageList.isEmpty()) {
			return;
		}
		List<LabExpendB> expendList = new ArrayList<>();
		for (int i = 0, s = wcDosageList.size(); i < s; i++) {
			Map<String, Object> dosage = wcDosageList.get(i);
			//	工控机的记录号
			String conExpendId = String.valueOf(dosage.get("FEID"));
			//	工控机的料仓信息,根据料仓信息查询出当前消耗的材料
			String storage = String.valueOf(dosage.get("FYlmc"));
			//	工控机的原料
			String bcsMaterial = String.valueOf(dosage.get("FYlmc"));
			//	erp的原料id
			Long erpMaterialId = null;
			//	工控机的原料id
			Long erpStorageId = null;
			SysStorageLog takeTimeOrStorage = sysStorageLogDao.findTakeTimeOrStorage(lineId, bcsMaterial, 1, batchTime);
			if (takeTimeOrStorage != null) {
				String erpMaterial = takeTimeOrStorage.getMaterial();
				erpMaterialId = takeTimeOrStorage.getMaterialId();
				erpStorageId = takeTimeOrStorage.getStorageId();
			}
			//	工控机的配方值(配合比设定值)
			Double recAmnt = Double.valueOf(String.valueOf(dosage.get("FPbsl")));
			//	工控机的设定值
			Double planAmnt = Double.valueOf(String.valueOf(dosage.get("FPbsl")));
			//	工控机的实际值(实际称量值)
			Double factAmnt = Double.valueOf(String.valueOf(dosage.get("FSysl")));
			//	工控机的含水率
			Double watFull = Double.valueOf(String.valueOf(dosage.get("FHsl")));
			if (watFull != null && watFull != 0d) {
				watFull = MathUtils.divide(watFull, 100d);
			}
			LabExpendB expend = new LabExpendB();
			expend.setInvoiceId(invoiceId);
			expend.setLineId(lineId);
			expend.setMaterialId(erpMaterialId);
			expend.setStorageId(erpStorageId);
			expend.setControlStorage(storage);
			expend.setBatchId(batchId);
			expend.setOptimizeId(levelOptimizeId);
			//	以下为工控机数据
			expend.setOptimizeQuantity(recAmnt);
			expend.setOptimizeWater(null);
			expend.setControlSetQuantity(planAmnt);
			expend.setControlRealQuantity(factAmnt);
			expend.setControlWater(watFull);
			//	截止数据
			expend.setCreator(bcsCreater);
			expend.setCreateTime(createDate);
			expend.setUseTime(batTime);
			expend.setConExpendId(conExpendId);
			expendList.add(expend);
		}

	}

	@Override
	public LabExpend queryByDosId(Long lineId, Long batchId, String dosId) {
		return null;
	}

	@Override
	public List<Long> writeBackB(Long lineId, List<LabExpendVoB> labExpends) {
		return null;
	}

}
